GCEでAssumeRoleWithWebIdentityを使用してアクセスキー情報なしで S3を操作してみる

GCEでAssumeRoleWithWebIdentityを使用してアクセスキー情報なしで S3を操作してみる

Clock Icon2025.01.21

概要

AWSのアクセスキーを使用せずにGoogle CloudからS3などのリソースにアクセスする必要があり、色々試した方法の一つとしてAssumeRoleWithWebIdentityを用いてGCEインスタンスからAWS CLIを実行する方法が良かったのでやり方をまとめてみました。

AssumeRoleWithWebIdentityとは

AssumeRoleWithWebIdentity は、AWS Security Token Service (STS)のAPIで、Web IDプロバイダー(OIDCプロバイダー)を使用して認証されたユーザーに一時的なセキュリティ認証情報(アクセスキー、シークレットキー、セッショントークン)を発行します。
AWSリソースへのアクセスを許可するために使用されます。この仕組みを用いることで、Google CloudのGCEインスタンスからS3を操作することができます。
(AWSのAssumeRoleを、AWS外からも使えるようにしたイメージの認証方法です。)
https://docs.aws.amazon.com/ja_jp/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html

認証をアクセスキーの情報ではなくロール(AssumeRoleWithWebIdentity)で行うことができ、アクセスキーの発行を行わないのでキーの流出に怯える日々から解放されます。

やりかた

流れとしては以下となります。

  1. サービスアカウント作成(uniqueId(一意のID)をメモる)
  2. AWSでIAMロールを作成。アイデンティティプロバイダーでGoogleを選択。(1でメモした値を設定)
  3. GCEインスタンスを構築。サービスアカウントに(1.)で作成したサービスアカウントを指定
  4. GCEインスタンスにSSH接続してAWS CLIをインストール
  5. AWS CLIのconfigを設定
  6. メタデータサーバからトークンを取得
  7. S3を操作

それでは一つ一つやってみます。

1. Google Cloudでサービスアカウントを作成

まず、AWSにアクセスするためのサービスアカウントを作成します。

  1. Google Cloudのコンソールにログインします。
  2. [IAMと管理 > サービスアカウント]に移動します。
  3. 「サービスアカウントを作成」をクリックします。
  4. 以下の情報を入力します:
    • サービスアカウント名: 任意の名前(例: aws-access-sa
    • サービスアカウントID: 任意の値を設定します
  5. 「作成して続行」をクリックします。
  6. 必要なロールを割り当てます。特にGoogle Cloudのサービスを使用しないのであれば何もロールを割り当てなくてもよいです。
  7. 作成したサービスアカウントの詳細ページを開き、uniqueId(一意のID) をメモします。

uniqueId(一意のID)の確認方法

  • サービスアカウントの詳細ページで、uniqueId(一意のID)(数値形式のID)を確認できます。
    スクリーンショット 2025-01-21 19.29.43.png

2. AWSでIAMロールを作成

次に、AWSでIAMロールを作成し、GoogleのOIDCプロバイダーを設定します。

  1. AWSマネジメントコンソールにログインします。
  2. [IAM > ロール]に移動します。
  3. 「ロールを作成」をクリックします。
  4. 信頼されたエンティティタイプで「ウェブアイデンティティ」を選択します。
  5. アイデンティティプロバイダーで「Google」を選択します。
  6. Audienceに手順1でメモした値(uniqueId(一意のID))を入力します。
    スクリーンショット 2025-01-21 19.22.06.png
  7. ポリシーをアタッチします:
    • 必要な権限を持つポリシーを選択します(S3を読み取るだけで良いのであればAmazonS3ReadOnlyAccess
  8. ロールの名前を入力(例: GoogleCloudAccessRole)し、作成します。

3. GCEインスタンスを構築

AWSにアクセスするGCEインスタンスを作成し、サービスアカウントを割り当てます。

  1. Google CloudのコンソールでCompute Engine > VMインスタンス に移動します。
  2. 「インスタンスを作成」をクリックします。
  3. マシンタイプなどは任意のものを設定します。インターネットへアクセスできるVPCに構築します。サービスアカウントは手順1で作成したサービスアカウントを選択します。
    スクリーンショット 2025-01-21 19.32.37.png

4. GCEインスタンスにAWS CLIをインストール

GCEインスタンスにSSH接続し、AWS CLIをインストールします。

  1. GCEインスタンスにSSHで接続します。Google CloudのコンソールからSSH接続します。

  2. AWS CLIをインストールします:

curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install

unzipコマンドが見つからない場合はインストールしてください。
Debianの場合ならsudo apt-get install unzipです。

  1. インストールを確認します:
aws --version

バージョン情報が出力されればインストール成功です。

5. AWS CLIの設定

AWS CLIの設定ファイルを作成し、IAMロールを使用するように設定します。

  1. AWS CLIの設定ファイルを編集します。regionだけ入力します。
aws configure

AWS Access Key ID [None]: 
AWS Secret Access Key [None]: 
Default region name [None]: ap-northeast-1
Default output format [None]: 
  1. configを開いて以下の内容を追加します:
vi ~/.aws/config

[profile google-role]
role_arn = arn:aws:iam::<AWS_ACCOUNT_ID>:role/GCPAccessRole
web_identity_token_file = /home/users/token.json
region = ap-northeast-1
  • role_arn: 手順2で作成したIAMロールのARN。
  • web_identity_token_file: メタデータサーバーから取得するトークンの保存先。出力先のパスは適宜変更してください。

6. メタデータサーバーからトークンを取得

GCEインスタンス内で、メタデータサーバーを使用してIDトークンを取得します。

  1. 以下のコマンドを実行してトークンを取得します:
curl -H "Metadata-Flavor: Google" \
"http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience=aws&format=full" \
-o /home/users/token.json
  1. トークンが正しく取得されたことを確認します:
cat /home/users/token.json

すこし脱線します。トークンについて深掘りします。
メタデータサーバからのレスポンス(token.jsonファイルの中身)はJWT(JSON Web Token)形式となっています。
以下の3つの部分で構成されています。それぞれ.(ドット)で区切られています。

  1. ヘッダー(Header): トークンのタイプや署名アルゴリズムを示します。
  2. ペイロード(Payload): トークンのデータが含まれています。
  3. 署名(Signature): トークンの改ざんを防ぐための署名。

token.json内のトークンを分割すると以下のイメージになります。

<ヘッダー>.<ペイロード>.<署名>

ペイロード部分をデコードすることで、トークンの有効期限や発行時刻を確認できます。
ペイロード部分はJWTの2番目の部分です。以下の手順でデコードします。

  1. トークンを.(ドット)で分割します。
  2. 1つ目のドット以降のペイロード部分を抜き出してbase64コマンドを用いてBase64URLデコードします。
echo "base64の文字列" | base64 -d
  • デコード結果:
{
  "aud": "aws",
  "azp": "***",
  "email": "gce-test@プロジェクトID.iam.gserviceaccount.com",
  "email_verified": true,
  "exp": 1737461494,
  "google": {
    "compute_engine": {
      "instance_creation_timestamp": 1737455486,
      "instance_id": "***",
      "instance_name": "***",
      "project_id": "***",
      "project_number": ***,
      "zone": "asia-northeast1-b"
    }
  },
  "iat": 1737457894,
  "iss": "https://accounts.google.com",
  "sub": "***"
}

デコード結果から、トークンの有効期限を確認することができます。

  • exp: トークンの有効期限(有効期限:Expiration Time)。UNIXタイムスタンプ形式の値です。
  • iat: トークンの発行時刻(発行時刻:Issued At)。UNIXタイムスタンプ形式の値です。

expiatUNIXタイムスタンプ形式で記録されているのでこれを人が読める形式に変換するには、以下のコマンドとなります。

$ date -d @1737460744
Tue Jan 21 12:45:44 UTC 2025

また、トークンの有効期間は、iat(発行時刻)からexp(有効期限)までの差で計算できます。

  • 有効期間: exp - iat = 1737461494 - 1737457894 = 3600秒(1時間)
    つまりこのトークンの有効期間は1時間とわかります。

7. S3を操作

AWS CLIを使用してS3バケットを操作します。

  1. AWS CLIでS3バケットのリストを取得します:
aws s3 ls --profile google-role
  1. S3バケット内のオブジェクトを確認します:
aws s3 ls s3://バケット名 --profile google-role
  1. 必要に応じて、ファイルのアップロードやダウンロードを行います:
aws s3 cp local-file.txt s3://バケット名/ --profile google-role

問題なく操作できていれば、成功です。アクセスキーを発行することなくGCEインスタンスからAWSのリソースをCLIやboto3で操作することができます。

所感

今回の仕組みはトークン更新の仕組みが入っていません。なのでトークン有効期間(1時間)経過後は再度トークンを取得し直す必要があるので注意が必要です。
しかしながら、アクセスキーなしでAWSにアクセスできるのアクセスキー流出リスクをなくすことができるのでとてもありがたいと思います。普段AWS CLIをほとんど使わず、障害対応時だけなど使用するというのであればこのような仕組みでAWSへアクセスするのもありかなと思います。

これ以外にもアクセスキーなしでAWSにGoogle Cloudからアクセスする方法はあるのでまた機会があればご紹介したいと思います。
それではまた。ナマステー

参考

https://cloud.google.com/compute/docs/metadata/overview?hl=ja

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.